﻿using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Collections;
using System.Runtime.CompilerServices;
using GeneralDFS.Common;
using GeneralDFS.Common.IO;
using GeneralDFS.DataEntity.Enum;
using GeneralDFS.DataEntity.IO;
using GeneralDFS.DataEntity.Nodes;

namespace GeneralDFS.BusinessLogical.IO
{
    public class Directory
    {
        private DirectoryNodeInfo _currentDir;

        /// <summary>
        /// 构造一个Dir的处理类
        /// </summary>
        /// <param name="node"></param>
        public Directory(NodeBase node) : this(node as DirectoryNodeInfo) { }

        /// <summary>
        /// 构造一个Dir的处理类
        /// </summary>
        /// <param name="node"></param>
        public Directory(DirectoryNodeInfo node)
        {
            if (node == null)
            {
                LogUtil.LogError("Directory构造函数中，参数node不能为空");
                return;
            }
            _currentDir = node;
            if (node.Childs == null)
                node.Init();
        }

        /// <summary>
        /// 设置当前操作目录(备用)
        /// </summary>
        /// <param name="dir"></param>
        public void SetCurrentDir(DirectoryNodeInfo dir)
        {
            _currentDir = dir;
        }

        /// <summary>
        /// 创建一个目录并返回
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public static DirectoryNodeInfo CreateDirectory(String name)
        {
            try
            {
                var node = new DirectoryNodeInfo
                    {
                        Name = name,
                        CreateTime = DateTime.Now.LongNow(),
                        LastUpdateTime = DateTime.Now.LongNow()
                    };
                return node;
            }
            catch (Exception ex)
            {
                LogUtil.LogError(ex.Message);
                return null;
            }
        }

        /// <summary>
        /// 断言目录已经实例化
        /// </summary>
        private void AssertNotNull()
        {
            Debug.Assert(_currentDir.Childs != null, "the dir has not inited!");
            Debug.Assert(_currentDir.Name != null, "the name is invaild");
        }

        /// <summary>
        /// 通过文件名或文件夹名称查找结点
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public int SearchChildren(String name)
        {
            return _currentDir.Childs.BinarySearch(new NodeBase { Name = name });
        }

        /// <summary>
        /// 添加一个文件夹或文件到列表
        /// </summary>
        /// <param name="newChild"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.Synchronized)]
        public int AddChildren(NodeBase newChild)
        {
            lock (_currentDir.Childs)
            {
                if (_currentDir.Childs == null)
                    _currentDir.Init();
                var index = SearchChildren(newChild.Name);
                if (index >= 0)
                {
                    return -1;
                }
                newChild.Parent = _currentDir;
                newChild.Depth = _currentDir.Depth + 1;
                newChild.FullPath = PathHelper.Combine(_currentDir.FullPath, newChild.Name);
                _currentDir.Childs.Insert(~index, newChild);

                return ~index;
            }
        }

        /// <summary>
        /// 通过名称删除文件或文件夹
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public Boolean RemoveChildren(String name)
        {
            AssertNotNull();
            var index = SearchChildren(name);
            if (index < 0)
                return false;
            _currentDir.Childs.RemoveAt(index);
            return true;
        }

        /// <summary>
        /// 清空所有文件或文件夹
        /// </summary>
        public void ClearChildrens()
        {
            _currentDir.Childs.Clear();
        }

        /// <summary>
        /// 替换为相同名称的节点(不可用做重命名)
        /// </summary>
        /// <param name="newChildren"></param>
        /// <returns></returns>
        public Boolean ReplaceChildren(NodeBase newChildren)
        {
            return RemoveChildren(newChildren.Name) && AddChildren(newChildren) >= 0;
        }

        /// <summary>
        /// 通过名称获取一个文件或文件夹
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public NodeBase GetChildren(String name)
        {
            if (_currentDir.Childs == null)
                return null;
            var index = SearchChildren(name);
            return index >= 0 ? _currentDir.Childs[index] : null;
        }

        /// <summary>
        /// 通过名称获取下一个文件或文件夹
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public NodeBase GetNextChildren(String name)
        {
            if (_currentDir.Childs == null)
                return null;
            var index = SearchChildren(name);
            return index + 1 < _currentDir.Childs.Count ? _currentDir.Childs[index + 1] : null;
        }

        /// <summary>
        /// 通过路径获取节点数组
        /// </summary>
        /// <param name="fullPath"></param>
        /// <param name="numOfNodes"></param>
        /// <returns></returns>
        public NodeBase[] GetNodesByPath(String fullPath, int numOfNodes)
        {
            if (PathHelper.CheckPathVaild(fullPath))
                return GetNodesByPath(PathHelper.Separate(fullPath), numOfNodes);
            return null;
        }

        /// <summary>
        /// 通过路径获取节点数组
        /// </summary>
        /// <param name="names"></param>
        /// <param name="numOfNodes"></param>
        /// <returns></returns>
        public NodeBase[] GetNodesByPath(String[] names, int numOfNodes)
        {
            var count = 0;
            NodeBase curNode = _currentDir;
            var curDir = new Directory(curNode);
            var nodes = new NodeBase[numOfNodes];
            var index = numOfNodes - names.Length;
            if (index > 0) index = 0;
            while (count < names.Length)
            {
                var lastComp = count == names.Length - 1;
                if (index >= 0)
                    nodes[index] = curNode;
                if (lastComp || !curDir._currentDir.IsDirectory())
                {
                    break;
                }
                curDir.SetCurrentDir(curNode as DirectoryNodeInfo);
                curNode = curDir.GetChildren(names[count + 1]);
                count++;
                index++;
            }
            return nodes;
        }

        /// <summary>
        /// 获取当前正在处理的目录
        /// </summary>
        /// <returns></returns>
        public DirectoryNodeInfo GetCurrentDir()
        {
            return _currentDir;
        }
    }
}